package com.ruoyi.iot.modbus.rtu;

import cn.hutool.json.JSONUtil;
import com.ruoyi.iot.utils.IEEE754Utils;
import com.serotonin.modbus4j.ModbusMaster;
import com.serotonin.modbus4j.exception.ModbusTransportException;
import com.serotonin.modbus4j.msg.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.binary.Hex;

import java.util.Arrays;


/**
 * @description: RTU工具类
 * @author: Howe
 * @create: 2019-12-02 13:08
 */
@Slf4j
public class Modbus4jRTUReadUtils {

    /**
     * @Description: 读取线圈
     * @Param: [master, slaveId, start, len]
     * @Return: boolean[]
     * @Author: Howe
     * @Date: 2019/12/2 13:33
     */
    public static String readCoil(ModbusMaster master, int slaveId, int start, int len) {

        try {
            ReadCoilsRequest request = new ReadCoilsRequest(slaveId, start, len);
            ReadCoilsResponse response = (ReadCoilsResponse) master.send(request);
            if (response.isException()) {
                log.error("readCoil Exception response: message={}", response.getExceptionMessage());
            } else {
                return stringBooleanData(response.getBooleanData());
            }
        } catch (ModbusTransportException e) {
            log.error("readCoil Exception", e);
        }
        return null;
    }

    /**
     * @Description: 读取离散寄存器
     * @Param: [master, slaveId, start, len]
     * @Return: boolean[]
     * @Author: Howe
     * @Date: 2019/12/2 13:34
     */
    public static String readDiscreteInput(ModbusMaster master, int slaveId, int start, int len) {

        try {
            ReadDiscreteInputsRequest request = new ReadDiscreteInputsRequest(slaveId, start, len);
            ReadDiscreteInputsResponse response = (ReadDiscreteInputsResponse) master.send(request);
            if (response.isException()) {
                log.error("readDiscreteInput Exception response: message={}", response.getExceptionMessage());
            } else {
                return stringBooleanData(response.getBooleanData());
            }
        } catch (ModbusTransportException e) {
            log.error("readDiscreteInput失败！！{}", e.getMessage());

        }
        return null;
    }


    /**
     * @Description: booleanData 取值第一条（按照一个属性一个地址取值）
     * @Param: [booleanData]
     * @Return: java.lang.String
     * @Author: Howe
     * @Date: 2019/12/17 16:32
     */
    private static String stringBooleanData(boolean[] booleanData) {

        if (booleanData != null && booleanData.length > 0) {
            return String.valueOf(booleanData[0]);
        } else {
            return null;
        }
    }

    /**
     * @Description: shortData 取值第一条（按照一个属性一个地址取值）
     * @Param: [shortData]
     * @Return: java.lang.String
     * @Author: Howe
     * @Date: 2019/12/17 16:32
     */
    private static String stringShortData(short[] shortData, String isChangeRegisterByte) {
        Double value = 0.0;
        if (shortData != null && shortData.length > 0) {
            if ("1".equals(isChangeRegisterByte)) {
                for (int i = 0; i < shortData.length; i++) {
                    value = shortData[shortData.length - 1 - i] * Math.pow(16, 4 * (shortData.length - 1 - i)) + value;
                }
            } else {
                for (int i = 0; i < shortData.length; i++) {
                    value = shortData[i] * Math.pow(16, 4 * (shortData.length - 1 - i)) + value;
                }
            }
            return String.valueOf(value);
        } else {
            return null;
        }
    }

    /**
     * @Description: 读取保持寄存器
     * @Param: [master, slaveId, start, len]
     * @Return: short[]
     * @Author: Howe
     * @Date: 2019/12/2 13:35
     */
    public static String readHoldingRegisters(ModbusMaster master, int slaveId, int start, int len, String type) {
        log.info("开始读取设备数据,slaveId:{},start:{}", slaveId, start);
        long time1 = System.currentTimeMillis();
        try {
            ReadHoldingRegistersRequest request = new ReadHoldingRegistersRequest(slaveId, start, len);
            ModbusResponse responses = master.send(request);
            log.info("=============================readHoldingRegisters.ModbusResponse:{}", JSONUtil.toJsonStr(responses));
            ReadHoldingRegistersResponse response = (ReadHoldingRegistersResponse) responses;
            log.info("=============================readHoldingRegisters.getShortData:{}", JSONUtil.toJsonStr(response.getShortData()));
            if (response.isException()) {
                log.error("=============================Exception response: message={}", response.getExceptionMessage());
            } else {
                String value = "";
                if ("floating_point".equals(type)) {
                    value = String.valueOf(IEEE754Utils.convertRegistersToFloat(response.getShortData()));
                } else if ("32_bit_Integer".equals(type)) {
                    return readLongDat(Hex.encodeHexString(response.getData()).toUpperCase());
                } else if ("64_bit_Integer".equals(type)) {
                    return readLongDat(Hex.encodeHexString(response.getData()).toUpperCase());
                } else {
                    log.info("readHoldingRegisters，等待开发{}", JSONUtil.toJsonStr(response.getShortData()));
                }
                long time2 = System.currentTimeMillis();
                log.info("结束读取设备数据,slaveId:{},start:{},耗时:{},属性值:{}", slaveId, start, time2 - time1, value);
                return value;
            }
        } catch (Exception e) {
            long time2 = System.currentTimeMillis();
            log.error("读取设备数据失败,slaveId:{},start:{},耗时:{}", slaveId, start, time2 - time1);
            log.error("读取设备数据失败,原因:{},", e.getMessage());
        }
        return null;
    }


    /**
     * @Description: 读取长整型的设备数据
     * @Param: null
     * @Return:
     * @Author: Howe
     * @Date: 2025/3/19 下午2:14
     **/
    public static String readLongDat(String data) {
        return Integer.parseInt(data, 16) + "";
    }


    /**
     * @Description: 读取输入寄存器
     * @Param: [master, slaveId, start, len]
     * @Return: short[]
     * @Author: Howe
     * @Date: 2019/12/2 13:35
     */
    public static String readInputRegisters(ModbusMaster master, int slaveId, int start, int len, String type) {

        try {
            ReadInputRegistersRequest request = new ReadInputRegistersRequest(slaveId, start, len);
            ReadInputRegistersResponse response = (ReadInputRegistersResponse) master.send(request);

            if (response.isException()) {
                log.error(String.format("Exception response: message=%s", response.getExceptionMessage()));
            } else {
                if ("float32".equals(type)) {
                    return String.valueOf(IEEE754Utils.convertRegistersToFloat(response.getShortData()));
                } else if ("32_bit_Integer".equals(type)) {
                    return readLongDat(Hex.encodeHexString(response.getData()).toUpperCase());
                } else if ("64_bit_Integer".equals(type)) {
                    return readLongDat(Hex.encodeHexString(response.getData()).toUpperCase());
                } else {
                    log.info("readInputRegisters没有转换的方法，等待开发{}", JSONUtil.toJsonStr(response.getShortData()));
                }
            }

        } catch (ModbusTransportException e) {
            log.error("readInputRegisters失败！！{}", e.getMessage());
        }
        return null;
    }

    /**
     * @Description: 写线圈
     * @Param: [master, slaveId, offset, value]
     * @Return: java.lang.String
     * @Author: Howe
     * @Date: 2019/12/2 13:35
     */
    public static String writeCoil(ModbusMaster master, int slaveId, int offset, boolean value) {

        try {
            WriteCoilRequest request = new WriteCoilRequest(slaveId, offset, value);
            WriteCoilResponse response = (WriteCoilResponse) master.send(request);

            if (response.isException()) {
                log.error("Exception response: message=" + response.getExceptionMessage());
            } else {
                return String.valueOf(value);
            }
        } catch (ModbusTransportException e) {
            log.error("writeCoil失败,原因:{},", e.getMessage());
        }
        return null;
    }

    /**
     * @Description: 写寄存器
     * @Param: [master, slaveId, offset, value]
     * @Return: java.lang.String
     * @Author: Howe
     * @Date: 2019/12/2 13:36
     */
    public static String writeRegister(ModbusMaster master, int slaveId, int offset, int value) {

        try {
            WriteRegisterRequest request = new WriteRegisterRequest(slaveId, offset, value);
            WriteRegisterResponse response = (WriteRegisterResponse) master.send(request);

            if (response.isException()) {
                log.error("Exception response: message={}", response.getExceptionMessage());
            } else {
                return String.valueOf(value);
            }
        } catch (ModbusTransportException e) {
            log.error("writeRegister失败,原因:{},", e.getMessage());
        }
        return null;
    }

    /**
     * @Description: 读异常状态
     * @Param: [master, slaveId]
     * @Return: java.lang.String
     * @Author: Howe
     * @Date: 2019/12/2 13:36
     */
    public static String readExceptionStatus(ModbusMaster master, int slaveId) {

        try {
            ReadExceptionStatusRequest request = new ReadExceptionStatusRequest(slaveId);
            ReadExceptionStatusResponse response = (ReadExceptionStatusResponse) master.send(request);

            if (response.isException()) {
                log.error(String.format("Exception response: message=%s", response.getExceptionMessage()));
            } else {
                return String.valueOf(response.getExceptionStatus());
            }
        } catch (ModbusTransportException e) {
            log.error("readExceptionStatus失败,原因:{},", e.getMessage());
        }
        return null;
    }

    /**
     * @Description: 报告人
     * @Param: [master, slaveId]
     * @Return: byte[]
     * @Author: Howe
     * @Date: 2019/12/2 13:52
     */
    public static byte[] reportSlaveId(ModbusMaster master, int slaveId) {

        try {
            ReportSlaveIdRequest request = new ReportSlaveIdRequest(slaveId);
            ReportSlaveIdResponse response = (ReportSlaveIdResponse) master.send(request);

            if (response.isException()) {
                log.error("reportSlaveId Exception response: message{}", response.getExceptionMessage());
            } else {
                return response.getData();
            }
        } catch (ModbusTransportException e) {
            log.error("reportSlaveId 失败,原因:{},", e.getMessage());
        }
        return null;
    }

    /**
     * @Description: 写多个线圈
     * @Param: [master, slaveId, start, values]
     * @Return: java.lang.String
     * @Author: Howe
     * @Date: 2019/12/2 13:37
     */
    public static String writeCoils(ModbusMaster master, int slaveId, int start, boolean[] values) {

        try {
            WriteCoilsRequest request = new WriteCoilsRequest(slaveId, start, values);
            WriteCoilsResponse response = (WriteCoilsResponse) master.send(request);

            if (response.isException()) {
                log.error("writeCoils Exception response: message={}", response.getExceptionMessage());
            } else {
                return Arrays.toString(values);
            }
        } catch (ModbusTransportException e) {
            log.error("writeCoils失败,原因:{},", e.getMessage());
        }
        return null;
    }

    /**
     * @Description: 写多个寄存器
     * @Param: [master, slaveId, start, values]
     * @Return: java.lang.String
     * @Author: Howe
     * @Date: 2019/12/2 13:37
     */
    public static String writeRegisters(ModbusMaster master, int slaveId, int start, short[] values) {

        try {
            WriteRegistersRequest request = new WriteRegistersRequest(slaveId, start, values);
            WriteRegistersResponse response = (WriteRegistersResponse) master.send(request);

            if (response.isException()) {
                log.error("writeRegisters Exception response: message={}", response.getExceptionMessage());
            } else {
                return "Success";
            }
        } catch (ModbusTransportException e) {
            log.error("writeRegisters失败,原因:{},", e.getMessage());
        }
        return null;
    }

    /**
     * @Description: 屏蔽寄存器
     * @Param: [master, slaveId, offset, and, or]
     * @Return: java.lang.String
     * @Author: Howe
     * @Date: 2019/12/2 13:46
     */
    public static String writeMaskRegister(ModbusMaster master, int slaveId, int offset, int and, int or) {

        try {
            WriteMaskRegisterRequest request = new WriteMaskRegisterRequest(slaveId, offset, and, or);
            WriteMaskRegisterResponse response = (WriteMaskRegisterResponse) master.send(request);

            if (response.isException()) {
                log.error("writeMaskRegister Exception response: message={}", response.getExceptionMessage());
            } else {
                return "Success";
            }
        } catch (ModbusTransportException e) {
            log.error("writeMaskRegister失败,原因:{},", e.getMessage());
        }
        return null;
    }

    /**
     * @Description: 数组转换 int[]
     * @Param: [a]
     * @Return: int[]
     * @Author: Howe
     * @Date: 2019/12/4 14:04
     */
    public static short[] strArrayToShortArray(String[] a) {
        short[] b = new short[a.length];
        for (int i = 0; i < a.length; i++) {
            b[i] = Short.parseShort(a[i]);
        }

        return b;
    }


    /**
     * @Description: 数组转换 boolean[]
     * @Param: [a]
     * @Return: boolean[]
     * @Author: Howe
     * @Date: 2019/12/4 14:04
     */
    public static boolean[] strArrayToBooleanArray(String[] a) {

        boolean[] b = new boolean[a.length];
        for (int i = 0; i < a.length; i++) {
            b[i] = Boolean.getBoolean(a[i]);
        }
        return b;
    }
}
